#ifndef __M_BD_H__
#define __M_BD_H__
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <iostream>
#include <unordered_map>
#include <memory>
#include <mutex>

namespace bitmq
{
    struct Binding
    {
        using ptr = std::shared_ptr<Binding>;
        std::string exchange_name;
        std::string msgqueue_name;
        std::string binding_key;

        Binding() {}
        Binding(const std::string &ename, const std::string &qname, const std::string &key) : exchange_name(ename), msgqueue_name(qname), binding_key(key)
        {
        }
    };
    // 队列与绑定信息是一一对应的
    // 一个交换机与绑定队列是一对多的关系
    // 通过队列名称获得与其对应的绑定信息
    using MsgQueueBindingMap = std::unordered_map<std::string, Binding::ptr>;
    // 通过交换机的名称获得所有与其对应的绑定队列的信息
    using BindingMap = std::unordered_map<std::string, MsgQueueBindingMap>;

    // 绑定信息持久化管理类
    class BindingMapper
    {
    public:
        BindingMapper(const std::string &dbfile) : _sql_helper(dbfile)
        {
            std::string path = FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(path);
            _sql_helper.open();
            createTable();
        }
        void createTable()
        {
            std::stringstream sql;
            sql << "create table if not exists binding_table(";
            sql << "exchange_name varchar(32),";
            sql << "msgqueue_name varchar(32),";
            sql << "binding_key varchar(128));";
            assert(_sql_helper.exec(sql.str(), nullptr, nullptr));
        }

        void removeTable()
        {
            std::string sql = "drop table if exists binding_table;";
            _sql_helper.exec(sql, nullptr, nullptr);
        }

        bool insert(Binding::ptr &binding)
        {
            std::stringstream ss;
            ss << "insert into binding_table values(";
            ss << "'" << binding->exchange_name << "',";
            ss << "'" << binding->msgqueue_name << "',";
            ss << "'" << binding->binding_key << "')";
            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        void remove(const std::string &ename, const std::string &qname)
        {
            std::stringstream ss;
            ss << "delete from binding_table where ";
            ss << "exchange_name= '" << ename << "' and ";
            ss << "msgqueue_name= '" << qname << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        void removeExchangeBindings(const std::string &ename)
        {
            std::stringstream ss;
            ss << "delete from binding_table where ";
            ss << "exchange_name= '" << ename << "' ; ";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        void removeMsgQueueBindings(const std::string &qname)
        {
            std::stringstream ss;
            ss << "delete from binding_table where ";
            ss << "msgqueue_name= '" << qname << "' ; ";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        BindingMap recovery()
        {
            BindingMap result;
            std::string sql = "select exchange_name,msgqueue_name,binding_key from binding_table;";
            _sql_helper.exec(sql, selectCallback, &result);
            return result;
        }

    private:
        static int selectCallback(void *arg, int numcol, char **row, char **fields)
        {
            BindingMap *result = static_cast<BindingMap *>(arg);
            auto bp = std::make_shared<Binding>(row[0], row[1], row[2]);
            MsgQueueBindingMap &qmap = (*result)[bp->exchange_name];
            qmap.insert(std::make_pair(bp->msgqueue_name, bp));
            return 0;
        }

    private:
        SqliteHelper _sql_helper;
    };

    // 绑定信息内存管理类--对外提供的接口
    class BindingManager
    {
    public:
        using ptr = std::shared_ptr<BindingManager>;
        BindingManager(const std::string &dbfile) : _mapper(dbfile)
        {
            _bindings = _mapper.recovery();
        }
        // 建立一个交换机与队列的绑定
        bool bind(const std::string &ename, const std::string &qname, const std::string &key, bool durable)
        {
            // 加锁，构造一个队列的绑定对象，添加映射关系
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _bindings.find(ename);
            if (it != _bindings.end() && it->second.find(qname) != it->second.end()) // 在交换机中存在与qname的绑定
            {
                return true;
            }
            Binding::ptr bp = std::make_shared<Binding>(ename, qname, key);
            if (durable)
            {
                bool ret = _mapper.insert(bp);
                if (ret == false)
                    return false;
            }
            auto &qbmap = _bindings[ename];
            qbmap.insert(std::make_pair(qname, bp));
            return true;
        }
        // 解除一个绑定
        void unBind(const std::string &ename, const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
            {
                return;
            } // 没有交换机相关的绑定信息
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
            {
                return;
            } // 交换机没有与该队列的绑定
            _mapper.remove(ename, qname);
            _bindings[ename].erase(qname);
        }
        // 移除所有与该交换机建立的绑定
        void removeExchangeBindings(const std::string &ename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeExchangeBindings(ename);
            _bindings.erase(ename);
        }

        // 移除所有与该队列建立的绑定
        void removeMsgQueueBindings(const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeMsgQueueBindings(qname);
            for (auto start = _bindings.begin(); start != _bindings.end(); ++start)
            {
                start->second.erase(qname);
            }
        }

        // 获得某个交换机的所有绑定信息
        MsgQueueBindingMap getExchangeBindings(const std::string &ename)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
            {
                return MsgQueueBindingMap();
            }
            return eit->second;
        }
        // 获得一个交换机和一个队列的绑定信息
        Binding::ptr getBinding(const std::string &ename, const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
            {
                return Binding::ptr();
            } // 没有交换机相关的绑定信息
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
            {
                return Binding::ptr();
            } // 交换机没有与该队列的绑定

            return qit->second;
        }
        bool exists(const std::string &ename, const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
            {
                return false;
            } // 没有交换机相关的绑定信息
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
            {
                return false;
            } // 交换机没有与该队列的绑定

            return true;
        }

        // 获得内存中所有的绑定关系数量
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            size_t total_size = 0;

            for (auto start = _bindings.begin(); start != _bindings.end(); ++start)
            {
                total_size += start->second.size();
            }
            return total_size;
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _bindings.clear();
        }

    private:
        std::mutex _mutex;
        BindingMapper _mapper;
        BindingMap _bindings;
    };
}

#endif